package player.ui.tree;



import java.io.File;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.WindowConstants;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.filechooser.FileSystemView;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;


public class FileSystemTreeModel implements TreeModel {

   public static void main(String[] args) {
      FileSystemTreeModel model = new FileSystemTreeModel();
      JTree tree = new JTree(model);
      tree.setCellRenderer(new FileSystemTreeRendererVideo());
      tree.setRootVisible(false);
      tree.setShowsRootHandles(true);
      JFrame app = new JFrame();
      app.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
      app.getContentPane().add(new JScrollPane(tree));
      app.setSize(300, 500);
      app.setLocationRelativeTo(null);
      app.setVisible(true);
   }

   private final Object fakeRoot = new Object();

   public FileSystemView fsv;

   private boolean hiddenVisible;


   private Collection<TreeModelListener> listeners;

   private File[] roots;
   
   static HashMap<File, Boolean> isFileTable=new HashMap<File, Boolean>();
   static HashMap<File, Boolean> isDirectoryTable=new HashMap<File, Boolean>();
   
   public static void init(){
	   
   }
   
   public static boolean isFile(File file){
	   if(!isFileTable.containsKey(file)){
		   isFileTable.put(file, file.isFile());
	   }
	   return isFileTable.get(file);
   }
   
   public static boolean isDirectory(File file){
	   if(!isDirectoryTable.containsKey(file)){
		   isDirectoryTable.put(file, file.isDirectory());
	   }
	   return isDirectoryTable.get(file);
   }


   private Comparator sortComparator = new Comparator() {

      public int compare(File a, File b) {
         Collator collator = Collator.getInstance();

         if (isDirectory(a) && isFile(b))
            return -1;
         else if (isFile(a) && isDirectory(b))
            return +1;

         int result = collator.compare(a.getName(), b.getName());
         if (result != 0)
            return result;

         result = collator.compare(a.getAbsolutePath(),
               b.getAbsolutePath());
         	return result;
      }

      public int compare(Object a, Object b) {
         return compare((File) a, (File) b);
      }
   };

   private HashMap sortedChildren;

   public FileSystemTreeModel() {
      this(FileSystemView.getFileSystemView());
   }

   public FileSystemTreeModel(FileSystemView fsv) {
      this(fsv, fsv.getRoots());
   }

   public FileSystemTreeModel(FileSystemView fsv, File[] roots) {
      this.fsv = fsv;
      this.roots = roots;

      listeners = new ArrayList<TreeModelListener>();
      sortedChildren = new HashMap();
   }

   public void addTreeModelListener(TreeModelListener listener) {
      if (listener != null && !listeners.contains(listener))
         listeners.add(listener);
   }

   public void fireTreeNodesChanged(TreeModelEvent event) {
      for (Iterator i = listeners.iterator(); i.hasNext();) {
         TreeModelListener listener = (TreeModelListener) i.next();
         listener.treeNodesChanged(event);
      }
   }

   public void fireTreeNodesInserted(TreeModelEvent event) {
      for (Iterator i = listeners.iterator(); i.hasNext();) {
         TreeModelListener listener = (TreeModelListener) i.next();
         listener.treeNodesInserted(event);
      }
   }

   public void fireTreeNodesRemoved(TreeModelEvent event) {
      for (Iterator i = listeners.iterator(); i.hasNext();) {
         TreeModelListener listener = (TreeModelListener) i.next();
         listener.treeNodesRemoved(event);
      }
   }

   public void fireTreeStructureChanged(TreeModelEvent event) {
      for (Iterator i = listeners.iterator(); i.hasNext();) {
         TreeModelListener listener = (TreeModelListener) i.next();
         listener.treeStructureChanged(event);
      }
   }

   public Object getChild(Object parent, int index) {
      if (parent == fakeRoot) {
         return roots[index];
      } else {
         List children = (List) sortedChildren.get(parent);
         return children == null ? null : children.get(index);
      }
   }

   public int getChildCount(Object parent) {
      if (parent == fakeRoot) {
         return roots.length;
      } else {
         File file = (File) parent;
         if (!fsv.isTraversable(file).booleanValue())
            return 0;

         

         if(!sortedChildren.containsKey(file)){
        	 File[] children = fsv.getFiles(file, !hiddenVisible);
             
             ArrayList<File> fl=new ArrayList<File>();
             for(int i=0;i<children.length;i++){
            	 File f=children[i];
            	 if(isDirectory(f)){
            		 fl.add(f);
            	 }
             }
             children=new File[fl.size()];
             for(int i=0;i<children.length;i++){
            	 children[i]=fl.get(i);
             }
             
             int nChildren = children == null ? 0 : children.length;
        	 TreeSet sorted = new TreeSet(sortComparator);
             for (int i = 0; i < nChildren; i++) {
                sorted.add(children[i]);
             }

             sortedChildren.put(file, new ArrayList(sorted));
         }
        
         int nChildren=((ArrayList)sortedChildren.get(file)).size();
         
         return nChildren;
      }
   }

   public int getIndexOfChild(Object parent, Object child) {
      List children = (List) sortedChildren.get(parent);
      if(children!=null){
    	  return children.indexOf(child);  
      }else{
    	  return 0;
      }
    
   }

   public Object getRoot() {
      return fakeRoot;
   }

   private Object[] getTreePath(Object obj) {
      List path = new ArrayList();
      while (obj != fakeRoot) {
         path.add(obj);
         obj = fsv.getParentDirectory((File) obj);
      }

      path.add(fakeRoot);

      int nElements = path.size();
      Object[] treePath = new Object[nElements];

      for (int i = 0; i < nElements; i++) {
         treePath[i] = path.get(nElements - i - 1);
      }

      return treePath;
   }

   public boolean isLeaf(Object node) {
      if (node == fakeRoot)
         return false;
      else
         return !fsv.isTraversable((File) node).booleanValue();
   }

   public void removeTreeModelListener(TreeModelListener listener) {
      if (listener != null)
         listeners.remove(listener);
   }

   public void valueForPathChanged(TreePath path, Object newValue) {
   }
}
